
/* copyright (c) 1996, 1997, 1998, 1999 William R. Pearson and the
   U. of Virginia */

/* $Name: fasta34t11d4 $ - $Id: showalign.c,v 1.21 2002/06/23 17:52:42 wrp Exp $ */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "defs.h"
#include "mm_file.h"

#include "mw.h"
#include "structs.h"
#include "param.h"
#define XTERNAL
#include "upam.h"
#undef XTERNAL

#if !defined(_CARBON) && defined(__MWERKS__)
extern void ChkEvent();
#endif

extern void (*ranlib) (char *str, int cnt,
		FSEEK_T libpos, char *libstr,
		struct lmf_str *lm_fd);

#define RANLIB (m_fptr->ranlib)

extern int (*getlib) (unsigned char *seq, int maxs,
		      char *libstr, int n_libstr,
		      FSEEK_T *libpos,
		      int *lcont,
		      long *l_off);

#define GETLIB (m_fptr->getlib)

extern struct lmf_str *
re_openlib(struct lmf_str *, int outtty);

extern double zs_to_bit(float, int, int);

void do_show(FILE *, unsigned char *, int ,
	     unsigned char *, int, int, char *, char *, int,
	     struct mngmsg, struct pstruct,
	     int *, int , struct a_struct *, long, void *);

int calcons(unsigned char *aa0, int n0,
	    unsigned char *aa1, int n1,
	    int *res, int nres, int *nc,
	    struct a_struct *aln, struct pstruct pst,
	    char *seqc0, char *seqc1,void *f_str);

void cal_coord(int n0, int n1, long sq0off, long loffset, struct a_struct *aln);

extern int do_walign(unsigned char *aa0, int n0,
		     unsigned char *aa1, int n1, int frame,
		     struct pstruct *ppst, void *f_str,
		     int **res, int *nres, struct a_struct *aln);

extern void discons(FILE *fd, struct mngmsg m_msg, struct pstruct pst,
		    char *seqc0, char *seqc1, int nc, 
		    int n0, int n1, char *name0, char *name1, int nml,
		    struct a_struct aln, long loffset);

extern void disgraph(FILE *fd, int n0, int n1, float percent, int score,
		     int min0, int min1, int max0, int max1,long sq0off,
		     char *name0, char *name1, int nml, int llen, int markx);

extern void aancpy(char *to, char *from, int count,
		   struct pstruct pst);

extern void
do_url(FILE *, struct mngmsg, struct pstruct, char *,  int,
       struct a_struct, long);

extern void
do_url1(FILE *, struct mngmsg, struct pstruct,	char *, int,
	struct a_struct , long);

extern void initseq(char **, char **, int);
extern void freeseq(char **, char **);

#ifndef A_MARK
#define A_MARK ">>"
#endif

static char l_name[200];

void showalign (FILE *fp, unsigned char **aa0, unsigned char *aa1, int maxn,
		struct beststr **bptr, int nbest,int qlib, struct mngmsg m_msg,
		struct pstruct pst, void **f_str, char *gstring2)
{
  unsigned char *aa1ptr;
  int ccont, lcont;
  long loffset, l_off;
  FSEEK_T lmark;
  int *res, nres;
  char libstr[20], tmp_str[20];
  char info_str[200];
  char bline[200], *bl_ptr, *bp, fmt[40];
  int tmp_len, l_llen;
  char name0[80], name0s[80], name1[200];
  int istart = 0, istop, i = 0, ib, nml;
  int n1tot;
  struct beststr *bbp;
  struct lmf_str *m_fptr;

  int n0, n1, maxt;
  int sw_score;

  n0 = m_msg.n0;

  if (m_msg.markx <= 9) nml = m_msg.nmlen; else nml=12;

  if (strlen(m_msg.libstr) > (size_t)0) {
    if (m_msg.libstr[0]=='>') strncpy(name0s,&m_msg.libstr[1],sizeof(name0s));
    else strncpy(name0s,m_msg.libstr,sizeof(name0s));
  }
  else {
    strncpy(name0s,m_msg.tname,sizeof(name0s));
  }
  name0s[sizeof(name0s)-1]='\0';

  if ((bp=strchr(name0s,' '))!=NULL) *bp='\0';

  l_llen = m_msg.aln.llen;
  if (m_msg.markx == 9) {
    l_llen += 40;
    if (l_llen > 200) l_llen=200;
  }

  sprintf(fmt,"%s%%-%ds (%%d %s)\n",A_MARK,l_llen-5,m_msg.sqnam);
    
  if (m_msg.markx <= 9) fprintf(fp,"\n");

  /*  fprintf (fp, "%3d %s\n", qlib,m_msg.libstr); */

  if (m_msg.ashow < 0) m_msg.ashow = m_msg.nshow;
  istart = 0; istop = min(min(nbest,m_msg.ashow),m_msg.nshow);

  for (ib=istart; ib<istop; ib++) {
    bbp = bptr[ib];
#ifdef SHOWUN
    if (bbp->nsfnum > 0 && sfn_cmp(m_msg.qsfnum,bbp->sfnum)) {
      istop = min(istop+1,nbest);
      continue;
    }
#endif
    if (pst.zsflag >= 0 && bbp->escore < m_msg.e_low) continue;
    if (bbp->score[0] <= 0) break;
    if ((m_fptr=re_openlib(bbp->m_file_p,!m_msg.quiet))==NULL)
      exit(1);

    if (m_msg.long_info) {
      RANLIB(bline,sizeof(bline),bbp->lseek,bbp->libstr,bbp->m_file_p);
      tmp_len = strlen(bline);
      bl_ptr = bline;
      if (m_msg.markx < 10) while (tmp_len > l_llen) {
	for (i=l_llen; i>10; i--)
	  if (bl_ptr[i]==' ') {
	    bl_ptr[i]='\n';
	    break;
	  }
	if (i <= 10) break;
	tmp_len -= i;
	bl_ptr += i;
      }
      bline[sizeof(bline)-1]='\0';
    }
    else if (m_msg.markx < 10){
      RANLIB(bline,l_llen-5,bbp->lseek,bbp->libstr,bbp->m_file_p);
      bline[l_llen-5]='\0';
    }
    else {
      RANLIB(bline,sizeof(bline),bbp->lseek,bbp->libstr,bbp->m_file_p);
      bline[sizeof(bline)-1]='\0';
      while ((bp=strchr(bline,'\n'))!=NULL) *bp=' ';
    }

    if (strlen(bline)==0) {
      bline[0]='>';
      strncpy(&bline[1],m_msg.lname,l_llen-5);
      bline[l_llen-5]='\0';
    }

    /*
    if (m_msg.nframe < 3) {
      maxt3 = maxn - m_msg.n0;
    }
    else {
      maxt3 = maxn-m_msg.n0-3; maxt3 -= maxt3%3; maxt3++;
    }
    */

    maxt = maxn;
    aa1ptr = aa1;
    loffset = 0l; lcont=0;
    for (ccont=0; ccont<=bbp->cont-1; ccont++) {

      n1=GETLIB(aa1ptr,maxt,libstr,sizeof(libstr),&lmark,&lcont,bbp->m_file_p,&l_off);

      if (aa1ptr!=aa1) n1 += m_msg.loff;

      if (lcont>bbp->cont-1) break;

      if (lcont) {
	maxt = m_msg.maxt3;
	memcpy(aa1,&aa1[n1-m_msg.loff],m_msg.loff);
	aa1ptr= &aa1[m_msg.loff];
	loffset += n1 - m_msg.loff;
      }
      else {
	maxt = maxn;
	aa1ptr=aa1;
      }
    }

    n1tot = (bbp->n1tot_p) ? *bbp->n1tot_p : bbp->n1;

  /* l_name is used to build an HTML link from the bestscore line to
     the alignment.  It can also be used to discriminate multiple hits
     from the same long sequence.  Text must match that in showbest.c */

    strncpy(name1,bline,sizeof(name1));
    name1[sizeof(name1)-1]='\0';
    if ((bp = strchr(name1,' '))!=NULL) *bp = '\0';
    strncpy(l_name,name1,sizeof(l_name));
    l_name[sizeof(l_name)-1]='\0';
    if ((bp=strchr(&l_name[3],'|'))!=NULL) *bp='\0';
    if (m_msg.nframe > 2) sprintf(&l_name[strlen(l_name)],"_%d",bbp->frame+1);
    else if (m_msg.qframe >= 0 && bbp->frame == 1)
      strncat(l_name,"_r",sizeof(l_name));
    if (bbp->cont-1 > 0) {
      sprintf(tmp_str,":%d",bbp->cont-1);
      strncat(l_name,tmp_str,sizeof(l_name));
    }

    if (m_msg.markx<=9) name1[nml]='\0';

/* print out score information; */

    if (m_msg.markx == 6) {
      fprintf (fp,"<A name=%s>\n<tt><pre>\n",l_name);
    }
    strncpy(name0,name0s,nml);
    name0[nml]='\0';

    if (pst.zsflag%10 == 6) {
      sprintf(info_str," comp: %.5lf H: %.5lf",bbp->comp,bbp->H);
    }
    else info_str[0]='\0';

    if (m_msg.markx < 4 || m_msg.markx==5 || m_msg.markx==6 || m_msg.markx==9) {
      fprintf (fp, fmt,bp=bline,n1tot);
      if (m_msg.nframe > 2) 
	fprintf (fp, "Frame: %d",bbp->frame+1);
      else if (m_msg.nframe > 1) 
	fprintf (fp, "Frame: %c",(bbp->frame? 'r': 'f'));
      else if (m_msg.qframe >= 0 && bbp->frame > 0 ) {
	  fputs("rev-comp",fp);
	  name0[nml-1]='\0';
	  strcat(name0,"-");
      }

      if (m_msg.arelv > 0)
	fprintf (fp, " %s: %3d", m_msg.alab[0],bbp->score[0]);
      if (m_msg.arelv > 1)
	fprintf (fp, " %s: %3d", m_msg.alab[1],bbp->score[1]);
      if (m_msg.arelv > 2)
	fprintf (fp, " %s: %3d", m_msg.alab[2],bbp->score[2]);
      fprintf(fp,"%s",info_str);
      if (pst.zsflag>=0) 
	fprintf (fp, "  Z-score: %4.1f  bits: %3.1f E(): %4.2g", 
		 bbp->zscore,zs_to_bit(bbp->zscore,n0,bbp->n1),bbp->escore);
      fprintf (fp, "\n");
    }
    else if (m_msg.markx==10) {
      fprintf(fp,">>%s\n",bline);
      if (m_msg.qframe > -1) {
	if (m_msg.nframe > 2) {
	  fprintf(fp,"; %s_frame: %d\n",m_msg.f_id0,bbp->frame+1);
	}
	else {
	  fprintf(fp,"; %s_frame: %c\n",m_msg.f_id0,(bbp->frame > 0? 'r':'f'));
	}
      }
      fprintf (fp, "; %s_%s: %3d\n", m_msg.f_id0,m_msg.alab[0],bbp->score[0]);
      if (m_msg.arelv > 1)
	fprintf (fp,"; %s_%s: %3d\n", m_msg.f_id0,m_msg.alab[1],bbp->score[1]);
      if (m_msg.arelv > 2)
	fprintf (fp,"; %s_%s: %3d\n", m_msg.f_id0,m_msg.alab[2],bbp->score[2]);
      if (info_str[0]) fprintf(fp,"; %s_info: %s\n",m_msg.f_id0,info_str);
      if (pst.zsflag>=0) 
     fprintf (fp,"; %s_z-score: %4.1f\n; %s_bits: %3.1f\n; %s_expect: %6.2g\n",
	      m_msg.f_id0,bbp->zscore,
	      m_msg.f_id0,zs_to_bit(bbp->zscore,n0,bbp->n1),
	      m_msg.f_id0,bbp->escore);
    }
      
/* print out alignment:

   (0) get sequence2
   (1) construct alignment using ALIGN (or l_band)
   (2) display alignment
*/

#if !defined(_CARBON) && defined(__MWERKS__)
	ChkEvent();
#endif
    sw_score=
      do_walign(aa0[bbp->frame],m_msg.n0, aa1, n1, bbp->frame, &pst,
		f_str[bbp->frame], &res, &nres, &m_msg.aln);
#if !defined(_CARBON) && defined(__MWERKS__)
    ChkEvent();
#endif

    if (nres > 0) 
      do_show(fp, aa0[bbp->frame], m_msg.n0, aa1, n1,
	      sw_score, name0, name1, nml,
	      m_msg, pst, res, nres, 
	      &m_msg.aln, loffset+l_off-1, f_str[bbp->frame]);

    if (m_msg.markx==6) fprintf(fp,"</pre></tt>\n<hr>\n");
    fflush(fp);
#if !defined(_CARBON) && defined(__MWERKS__)
	ChkEvent();
#endif
  }
  if (fp!=stdout) fprintf(fp,"\n");
}

void do_show(FILE *fp, unsigned char *aa0, int n0,
	     unsigned char *aa1, int n1, int score,
	     char *name0, char *name1, int nml,
	     struct mngmsg m_msg, struct pstruct pst, 
	     int *res, int nres, struct a_struct *aln,
	     long loffset, void *f_str)
{
  int nident, lc, nc, ngap;
  float percent, gpercent;
  char *seqc0, *seqc1;
  int maxc;

  if (aln->showall==1) {
    maxc = nres + max(aln->min0,aln->min1)+
      max((n0-aln->max0),(n1-aln->max1))+4;
    initseq(&seqc0, &seqc1, maxc);
  }
  else {
    maxc = nres + 4*aln->llen+4;
    initseq(&seqc0, &seqc1, maxc);
  }

  nc=calcons(aa0,n0,aa1,n1,res,nres, &lc,aln,pst, seqc0, seqc1, f_str);

  nident = aln->nident;
  if (lc > 0) percent = (100.0*(float)nident)/(float)lc;
  else percent = -1.00;

  ngap = aln->ngap_q + aln->ngap_l;
  if (lc-ngap> 0) gpercent = (100.0*(float)nident)/(float)(lc-ngap);
  else gpercent = -1.00;

  cal_coord(n0,n1,m_msg.sq0off,loffset,aln);

  if (m_msg.markx < 4 || m_msg.markx == 5 || m_msg.markx==6 || m_msg.markx==9) {
    if (pst.sw_flag) {
      fprintf(fp,"Smith-Waterman score: %d; ",score);
    }
    else {
      fprintf(fp,"banded Smith-Waterman score: %d; ",score);
    }
    fprintf(fp," %6.3f%% identity",percent);
#ifndef NO_UNGAPPED
    fprintf(fp," (%6.3f%% ungapped)",gpercent);
#endif
    fprintf(fp," in %d %s overlap",lc,m_msg.sqnam);

    fprintf(fp," (%ld-%ld:%ld-%ld)\n",
	    aln->d_start0,aln->d_stop0,aln->d_start1,aln->d_stop1);

    if (m_msg.markx == 6) {
      do_url1(fp, m_msg, pst, l_name,n1,*aln,loffset);
    }

    if (m_msg.markx==5 || m_msg.markx==6) {
      fputc('\n',fp);
#ifndef FASTX
      disgraph(fp, n0, n1, percent, score, aln->min0, aln->min1,
	       aln->max0, aln->max1, m_msg.sq0off,
	       name0, name1, nml, m_msg.aln.llen, m_msg.markx);
#else
      disgraph(fp, n0/3, n1, percent, score, aln->min0/3, aln->min1,
	       aln->max0/3, aln->max1, m_msg.sq0off,
	       name0, name1, nml, m_msg.aln.llen, m_msg.markx);
#endif
    }

    discons(fp, m_msg, pst, seqc0, seqc1, nc, n0, n1, name0, name1, nml,
	    *aln, loffset);
    fputc('\n',fp);
  }
  else if (m_msg.markx == 4)
#ifndef FASTX
    disgraph(fp, n0, n1, percent, score,aln->min0, aln->min1,
	     aln->max0, aln->max1, m_msg.sq0off,
	     name0, name1, nml, m_msg.aln.llen, m_msg.markx);
#else
    disgraph(fp, n0/3, n1, percent, score,
	     aln->min0/3, aln->min1, aln->max0/3, aln->max1,
	     m_msg.sq0off, name0, name1, nml, m_msg.aln.llen,
	     m_msg.markx);
#endif

/*
  else if (m_msg.markx==9) {
    fprintf(fp,"\t%5.3f\t%4d\t%4ld\t%4ld\t%4ld\t%4ld\n",
	    percent/100.0,lc,
	    aln->d_start0,aln->d_stop0,
	    aln->d_start1,aln->d_stop1);
  }
*/
  else if (m_msg.markx==10) {
    if (pst.sw_flag && m_msg.arelv>0)
      fprintf(fp,"; %s_score: %d\n",m_msg.f_id1,score);
    fprintf(fp,"; %s_ident: %5.3f\n",m_msg.f_id1,percent/100.0);
    fprintf(fp,"; %s_gident: %5.3f\n",m_msg.f_id1,gpercent/100.0);
    fprintf(fp,"; %s_overlap: %d\n",m_msg.f_id1,lc);
    discons(fp, m_msg, pst, seqc0, seqc1, nc, n0, n1, name0, name1, nml,
	    *aln, loffset);
  }
  freeseq(&seqc0,&seqc1);
}

void initseq(char **seqc0, char **seqc1, int seqsiz)	/* initialize arrays */
{
  *seqc0=(char *)calloc((size_t)seqsiz,sizeof(char));
  *seqc1=(char *)calloc((size_t)seqsiz,sizeof(char));
  if (*seqc0==NULL || *seqc1==NULL)
    {fprintf(stderr,"cannot allocate consensus arrays %d\n",seqsiz);
     exit(1);}
}

void freeseq(char **seqc0, char **seqc1)
{
  free(*seqc0); free(*seqc1);
}
